// -----------------------------------------------------------------------
// Copyright (c) 2008, Stone Steps Inc. 
// All rights reserved
// http://www.stonesteps.ca/legal/bsd-license/
//
// This is a BBCode parser written in JavaScript. The parser is intended
// to demonstrate how to parse text containing BBCode tags in one pass 
// using regular expressions.
//
// The parser may be used as a backend component in ASP or in the browser, 
// after the text containing BBCode tags has been served to the client. 
//
// Following BBCode expressions are recognized:
//
// [b]bold[/b]
// [i]italic[/i]
// [u]underlined[/u]
// [s]strike-through[/s]
// [samp]sample[/samp]
//
// [color=red]red[/color]
// [color=#FF0000]red[/color]
// [size=1.2]1.2em[/size]
//
// [url]http://blogs.stonesteps.ca/showpost.asp?pid=33[/url]
// [url=http://blogs.stonesteps.ca/showpost.asp?pid=33][b]BBCode[/b] Parser[/url]
//
// [q=http://blogs.stonesteps.ca/showpost.asp?pid=33]inline quote[/q]
// [q]inline quote[/q]
// [blockquote=http://blogs.stonesteps.ca/showpost.asp?pid=33]block quote[/blockquote]
// [blockquote]block quote[/blockquote]
//
// [pre]formatted 
//     text[/pre]
// [code]if(a == b) 
//   print("done");[/code]
//
// text containing [noparse] [brackets][/noparse]
//
// -----------------------------------------------------------------------
var opentags;           // open tag stack
var crlf2br = true;     // convert CRLF to <br>?
var noparse = false;    // ignore BBCode tags?
var urlstart = -1;      // beginning of the URL if zero or greater (ignored if -1)

// aceptable BBcode tags, optionally prefixed with a slash
var tagname_re = /^\/?(?:b|i|u|pre|samp|code|colou?r|size|noparse|url|s|q|quote|blockquote|img|left|right)$/;

// color names or hex color
var color_re = /^(:?black|silver|gray|white|maroon|red|purple|fuchsia|green|lime|olive|yellow|navy|blue|teal|aqua|#(?:[0-9a-f]{3})?[0-9a-f]{3})$/i;

// numbers
var number_re = /^[\\.0-9]{1,8}$/i;

// reserved, unreserved, escaped and alpha-numeric [RFC2396]
var uri_re = /^[-;\/\?:@&=\+\$,_\.!~\*'\(\)%0-9a-z]{1,512}$/i;

var url_re = /(https?:\/\/)?www\..*\.(?:png|jpg|jpeg|gif)$/i

// main regular expression: CRLF, [tag=option], [tag] or [/tag]
var postfmt_re = /([\r\n])|(?:\[([a-z]{1,16})(?:=([^\x00-\x1F"'\(\)<>\[\]]{1,256}))?\])|(?:\[\/([a-z]{1,16})\])/ig;

// Image regex
var img_re = /^[^\*\<\>]*\.(jpg|png|gif|jpeg)$/i;

// stack frame object
function taginfo_t(bbtag, etag)
{
   this.bbtag = bbtag;
   this.etag = etag;
}

// check if it's a valid BBCode tag
function isValidTag(str)
{
   if(!str || !str.length)
      return false;

   return tagname_re.test(str);
}

//
// m1 - CR or LF
// m2 - the tag of the [tag=option] expression
// m3 - the option of the [tag=option] expression
// m4 - the end tag of the [/tag] expression
//
function textToHtmlCB(mstr, m1, m2, m3, m4, offset, string)
{
   //
   // CR LF sequences
   //
   if(m1 && m1.length) {
      if(!crlf2br)
         return mstr;

      switch (m1) {
         case '\r':
            return "";
         case '\n':
            return "<br>";
      }
   }

   //
   // handle start tags
   //
   if(isValidTag(m2)) {
      // if in the noparse state, just echo the tag
      if(noparse)
         return "[" + m2 + "]";

      // ignore any tags if there's an open option-less [url] tag
      if(opentags.length && opentags[opentags.length-1].bbtag == "url" && urlstart >= 0)
         return "[" + m2 + "]";

      switch (m2) {
         case "code":
            opentags.push(new taginfo_t(m2, "</code></pre>"));
            crlf2br = false;
            return "<pre><code>";

         case "pre":
            opentags.push(new taginfo_t(m2, "</pre>"));
            crlf2br = false;
            return "<pre>";

         case "color":
         case "colour":
            if(!m3 || !color_re.test(m3))
               m3 = "inherit";
            opentags.push(new taginfo_t(m2, "</span>"));
            return "<span style=\"color: " + m3 + "\">";

         case "size":
            if(!m3 || !number_re.test(m3))
               m3 = "1";
            opentags.push(new taginfo_t(m2, "</span>"));
            return "<span style=\"font-size: " + Math.min(Math.max(m3, 0.7), 3) + "em\">";

         case "s":
            opentags.push(new taginfo_t(m2, "</span>"));
            return "<span style=\"text-decoration: line-through\">";

         case "noparse":
            noparse = true;
            return "";

         case "url":
            opentags.push(new taginfo_t(m2, "</a>"));
            
            // check if there's a valid option
            if(m3 && uri_re.test(m3)) {
               // if there is, output a complete start anchor tag
               urlstart = -1;
               return "<a href=\"" + m3 + "\">";
            }

            // otherwise, remember the URL offset 
            urlstart = mstr.length + offset;

            // and treat the text following [url] as a URL
            return "<a href=\"";
            
        case "img":
            if (img_re.test(m3)) {
                if (url_re.test(m3)) {
                    if (m3.indexOf("http://") !== 0)
                    {
                        m3 = 'http://' + m3;
                    }
                    return "<img src=\"" + m3 + "\" width= />";
                }
                else{
                    return "<img src=\"" + baseurl + 'img/uploads/' + m3 + "\" />";
                }    
            }
            return "";
            

         case "q":
         case "quote":
         case "blockquote":
            opentags.push(new taginfo_t(m2, "</" + m2 + ">"));
            return m3 && m3.length && uri_re.test(m3) ? "<" + m2 + " cite=\"" + m3 + "\">" : "<" + m2 + ">";

        case "b":
            opentags.push(new taginfo_t(m2, "</strong>"));
            return "<strong>";
        case "left":
            opentags.push(new taginfo_t(m2, "</span><span style=\"clear:left;\"/>"));
            return "<span style=\"float:left;\">";
        case "right":
            opentags.push(new taginfo_t(m2, "</span><span style=\"clear:right;\"/>"));
            return "<span style=\"float:right;\">";

         default:
            // [samp], [b], [i] and [u] don't need special processing
            opentags.push(new taginfo_t(m2, "</" + m2 + ">"));
            return "<" + m2 + ">";
            
      }
   }

   //
   // process end tags
   //
   if(isValidTag(m4)) {
      if(noparse) {
         // if it's the closing noparse tag, flip the noparse state
         if(m4 == "noparse")  {
            noparse = false;
            return "";
         }
         
         // otherwise just output the original text
         return "[/" + m4 + "]";
      }
      
      // highlight mismatched end tags
      if(!opentags.length || opentags[opentags.length-1].bbtag != m4)
         return "<span style=\"color: red\">[/" + m4 + "]</span>";

      if(m4 == "url") {
         // if there was no option, use the content of the [url] tag
         if(urlstart > 0)
            return "\">" + string.substr(urlstart, offset-urlstart) + opentags.pop().etag;
         
         // otherwise just close the tag
         return opentags.pop().etag;
      }
      else if(m4 == "code" || m4 == "pre")
         crlf2br = true;

      // other tags require no special processing, just output the end tag
      return opentags.pop().etag;
   }

   return mstr;
}

//
// post must be HTML-encoded
//
function parseBBCode(post)
{
   var result, endtags, tag;

   // convert CRLF to <br> by default
   crlf2br = true;

   // create a new array for open tags
   if(opentags == null || opentags.length)
      opentags = new Array(0);

   // run the text through main regular expression matcher
   result = post.replace(postfmt_re, textToHtmlCB);

   // reset noparse, if it was unbalanced
   if(noparse)
      noparse = false;
   
   // if there are any unbalanced tags, make sure to close them
   if(opentags.length) {
      endtags = new String();
      
      // if there's an open [url] at the top, close it
      if(opentags[opentags.length-1].bbtag == "url") {
         opentags.pop();
         endtags += "\">" + post.substr(urlstart, post.length-urlstart) + "</a>";
      }
      
      // close remaining open tags
      while(opentags.length)
         endtags += opentags.pop().etag;
   }

   return endtags ? result + endtags : result;
}

function insertBBCodeTag(element, tag, endingTag) {
    // insert tag such as 'code' and set the current cursor position to after
    // the first tag
    var start = 0;
    
    if (endingTag === undefined) endingTag = true;
    
    var endTag = tag;
    
    if (tag.indexOf("=") !== -1){
        endTag = tag.substr(0, tag.indexOf("="));
    }
    
    if (document.selection !== undefined) {
        // Internet explorer
        element.focus(); 
        var original = element.value.replace(/\r\n/g, "\n"); 
        var range = document.selection.createRange(); 

        if(range.parentElement() != element)
        { 
            return false; 
        } 
        if (endingTag) {
            range.text = '[' + tag + ']' + range.text + '[/' + endTag + ']';
        }
        else
        {
            range.text = '[' + tag + ']' + range.text;
        }
     
        var actual = tmp = element.value.replace(/\r\n/g, "\n"); 

        for(var diff = 0; diff < orig.length; diff++) 
        { 
            if(original.charAt(diff) != actual.charAt(diff)) 
            {
                break; 
            }
        } 

        for(index = 0, start = 0;  
        
            tmp.match(text)  
            && (tmp = tmp.replace(text, ""))  
            && index <= diff;  
        
            index = start + text.length 
            ) 
            { 
                start = actual.indexOf(text, index); 
            } 
            
            setCaretTo(element, start);
    }
    else if (element.selectionStart !== undefined) {
        // Gecko
        start = element.selectionStart;
        var end = element.selectionEnd;
        

        startText = element.value.substr(0, start);
        endText = element.value.substr(end, element.value.length);
        betweenText = element.value.substr(start, end-start);

        if (endingTag)
        {
            element.value = startText + '[' + tag + ']' + betweenText + '[/' + endTag + ']' + endText;
        }
        else
        {
            element.value = startText + '[' + tag + ']' + betweenText + endText;;
        }

        setCaretTo(element, start + tag.length + 2);
        
        return true;
    }
    else {
        return false;
    }
    return false;
}

function setCaretTo(element, position) {
    if(element.createTextRange !== undefined) { 
        /* Create a TextRange, set the internal pointer to
           a specified position and show the cursor at this
           position
        */ 
        var range = element.createTextRange(); 
        range.move("character", position); 
        range.select(); 
    } else if (element.selectionStart !== undefined) { 
        /* Gecko is a little bit shorter on that. Simply
           focus the element and set the selection to a
           specified position
        */ 
        element.focus(); 
        element.setSelectionRange(position, position); 
    } 
}

function previewBBCode(bbcode) {
    html = parseBBCode(bbcode);
    element = document.getElementById("overlay_preview");
    if (element === undefined || element === null) 
    {
        element = document.createElement('div');
        
        element.id = "overlay_preview";
        document.getElementsByTagName('body')[0].appendChild(element);
    }
    
    element.className = "white_content";
    element.style.display = 'block';
    element.innerHTML = html;
    
    document.getElementById("fadebox").style.display = "block";
}

function unpreview() {
    if (query_active)
    {
        for (i = 0; i < query_questions.length; ++i)
        {
            var element = document.getElementById("query_value_" + i);
            if (element && element.value)
            {
                insertBBCodeTag(document.getElementById('body_text'), query_tag + element.value, query_end_tag);
            }
        }
        query_active = false;
        
        query_tag = null;
        
        query_questions = null;
        
        query_end_tag = undefined;
    }
    document.getElementById("overlay_preview").style.display = "none";
    document.getElementById("fadebox").style.display = "none";
}

var query_active = false;

var query_tag = null;

var query_questions = null;

var query_end_tag = undefined;

function queryValue(tag, questions, end_tag) {
    element = document.getElementById('overlay_preview');
    if (element === undefined || element === null) 
    {
        element = document.createElement('div');
        element.className += "white_content";
        element.id = "overlay_preview";
        document.getElementsByTagName('body')[0].appendChild(element);
    }
    element.className = "white_content queryvalue";
    
    element.innerHTML = '<form id="query_value_form" action="#">';
    for (i = 0; i < questions.length; ++i)
    {
        element.innerHTML += '<label for="query_value_' + i + '">' + questions[i] + '</label>';
        element.innerHTML += '<input type="text" name="query_value_'+i+'" id="query_value_' + i + '"/><br/>';
    }
    element.innerHTML += '<input type="submit" value="Okay" onClick="unpreview(); return false;"/></form>';
    element.style.display = 'block';
    query_end_tag = end_tag;
    query_active = true;
    query_tag = tag;
    query_questions = questions;
    document.getElementById("fadebox").style.display = "block";
}

function selectColourCode()
{
    if ($("#colourcode").val())
    {
        insertBBCodeTag($("#body_text")[0], "color=" + $("#colourcode").val());
    }
    $("#colourcode")[0].selectedIndex = 0;
}

function fileUploader()
{
    element = document.getElementById("flash_uploader");
    if (!element)
    {
        element = document.createElement("form");
        element.enctype = "multipary/form-data";
        element.action = baseurl + 'FileProcessor/UploadFiles';
        element.method = "POST";
        element.id = "flash_uploader";
        element.className = "flash_form";
        element.style.display = "inline;"
        element.innerHTML = '<fieldset><legend>Upload your file</legend> <ol> <li id="example3"> <label for="example3_field">Choose a file to upload:</label> <input name="myFile3" id="submit_field"  type="file" /> </li> </ol> </fieldset> <input type="submit" name="submit" value="Upload File" />';
    }
    element.style.display = "inline";
    element2 = document.getElementById('overlay_preview');
    
    if (element2 === undefined || element2 === null) 
    {
        element2 = document.createElement('div');
        element2.id = "overlay_preview";
        $('body')[0].appendChild(element2);
    }
    element2.innerHTML = '';
    element2.appendChild(element);
    element2.className = "white_content flash_uploader";
    
    element2.style.display = 'block';

    document.getElementById("fadebox").style.display = "block";
    $("#submit_field").jqUploader({background:	"FFFFDF",
                                   barColor:	"FF00FF",
                                   allowedExt:     "*.jpg; *.jpeg; *.png; *.gif",
                                   allowedExtDescr: "Images (*.jpg; *.jpeg; *.png; *.gif)",
                                   debug:0,
                                   hideSubmit:true,
                                   src: baseurl + 'script/jqUploader.swf'});
}

function insertFile()
{
    if ($("#flash_uploader"))
    {
        var hidden = $("*[type='hidden']", $("#flash_uploader"));
        if (hidden.length > 0)
        {
            insertBBCodeTag($("#body_text")[0], "img=" + hidden[0].value, false);
            unpreview();
        }
    }
}

 $(document).ready(function(){
    //$('#example1').jqUploader({
    //    debug:0
//        ,background:'FFFFDF'
///        ,barColor:'FFDD00'
//        ,allowedExt:'*.avi; *.jpg; *.jpeg; *.png'
//        ,allowedExtDescr: 'what you want'
//        ,validFileMessage: 'Thanks, now hit Upload!'
//        ,endMessage: 'and don\'t you come back ;)'
//        ,hideSubmit: false
//    });
//    $("#example2").jqUploader({
//        afterScript:	"redirected.php",
//        background:	"FFFFDF",
//        barColor:	"64A9F6",
//        allowedExt:     "*.avi; *.jpg; *.jpeg; *.png",
//        allowedExtDescr: "Images and movies (*.avi; *.jpg; *.jpeg; *.png)"
//    });

    $("#submit_field").jqUploader({background:	"FFFFDF",
                                   barColor:	"FF00FF",
                                   allowedExt:     "*.jpg; *.jpeg; *.png; *.gif",
                                   allowedExtDescr: "Images (*.jpg; *.jpeg; *.png; *.gif)",
                                   debug:0,
                                   hideSubmit:true,
                                   src: baseurl + 'script/jqUploader.swf'});
});